//////////////////////////////////////////////////////////////////////////
//
// GAM203
// Quad
// Quad.cpp
// 
// Grant Johnson
// Qantm College
// 27/10/2010
//
//////////////////////////////////////////////////////////////////////////

#include "ParticleQuad.h"
#include <stdio.h>
#include <d3dx9.h>
#include "Shader.h"
#include "ShaderMgr.h"
#include "RenderParams.h"
#include "Renderer.h"

static const int VERTEX_COUNT = 4;
static const int INDEX_COUNT = 4;

ParticleQuad::ParticleQuad()
: m_pVertexBuffer(NULL)
, m_pIndexBuffer(NULL)
, m_pTex(NULL)
{
	D3DXMatrixIdentity(&m_worldMatrix);
	m_alpha = 255;
	m_pTexFilename = new char[256];
}

ParticleQuad::~ParticleQuad()
{
	//Cleanup
	if (m_pTex)
	{
		m_pTex->Release();
		m_pTex = NULL;
	}
	if(m_pTexFilename)
	{
		delete m_pTexFilename;
		m_pTexFilename = NULL;
	}
	if(m_pVertexBuffer)
	{
		m_pVertexBuffer->Release();
		m_pVertexBuffer = NULL;
	}
	if(m_pIndexBuffer)
	{
		m_pIndexBuffer->Release();
		m_pIndexBuffer = NULL;
	}
}

bool ParticleQuad::CreateObject(IDirect3DDevice9* a_pDevice, char* a_pTexFileName)
{
	//No device was given
	if (!a_pDevice)
	{
		return false;
	}

	//Copy over the filename for the texture, sprintf_s ensures it's not NULL
	sprintf_s(m_pTexFilename, 256, "%s", a_pTexFileName);

	HRESULT result;

	//Create a texture
	result = D3DXCreateTextureFromFile(a_pDevice, m_pTexFilename, &m_pTex);
	if (FAILED(result))
	{
		return false;
	}

	//Create the vertex buffer
	result = a_pDevice->CreateVertexBuffer(sizeof(VertexData) * VERTEX_COUNT, 0, VERTEX_FORMAT, D3DPOOL_DEFAULT, &m_pVertexBuffer, NULL);
	if (result != D3D_OK)
	{
		//Vertex buffer creation failed; clean up before we return
		if (m_pTex)
		{
			m_pTex->Release();
			m_pTex = NULL;
		}
		return false;
	}

	//Create the index buffer
	a_pDevice->CreateIndexBuffer(sizeof(short) * INDEX_COUNT, 0, D3DFMT_INDEX16,D3DPOOL_DEFAULT, &m_pIndexBuffer, NULL);
	if (result != D3D_OK)
	{
		//Index buffer creation failed, but vertex buffer was created! Clean up before we return
		if (m_pTex)
		{
			m_pTex->Release();
			m_pTex = NULL;
		}
		m_pVertexBuffer->Release();
		m_pVertexBuffer = NULL;
		return false;
	}

	//Create an array of vertex data on the stack
	VertexData verts[VERTEX_COUNT];

	const float QUAD_HALF_SIZE = 1.0f;
	verts[0].pos = D3DXVECTOR3(-QUAD_HALF_SIZE,  QUAD_HALF_SIZE, 0);
	verts[1].pos = D3DXVECTOR3( QUAD_HALF_SIZE,  QUAD_HALF_SIZE, 0);
	verts[2].pos = D3DXVECTOR3(-QUAD_HALF_SIZE, -QUAD_HALF_SIZE, 0);
	verts[3].pos = D3DXVECTOR3( QUAD_HALF_SIZE, -QUAD_HALF_SIZE, 0);

	verts[0].norm = D3DXVECTOR3(0, 1, 0);
	verts[1].norm = D3DXVECTOR3(0, 1, 0);
	verts[2].norm = D3DXVECTOR3(0, 1, 0);
	verts[3].norm = D3DXVECTOR3(0, 1, 0);

	verts[0].col = D3DCOLOR_ARGB(255, 255, 255, 255);
	verts[1].col = D3DCOLOR_ARGB(255, 255, 255, 255);
	verts[2].col = D3DCOLOR_ARGB(255, 255, 255, 255);
	verts[3].col = D3DCOLOR_ARGB(255, 255, 255, 255);

	verts[0].u = 0.0f; verts[0].v = 0.0f;
	verts[1].u = 1.0f; verts[1].v = 0.0f;
	verts[2].u = 0.0f; verts[2].v = 1.0f;
	verts[3].u = 1.0f; verts[3].v = 1.0f;

	//Create an array of index data on the stack
	short indices[INDEX_COUNT];
	//Only need 4 indices if we draw the quad as a triangle STRIP, not a triangle LIST
	indices[0] = 0;
	indices[1] = 1;
	indices[2] = 2;
	indices[3] = 3;

	//Copy vertex data into vertex buffer
	void* pLockedData = NULL;
	m_pVertexBuffer->Lock(0, sizeof(VertexData) * VERTEX_COUNT, &pLockedData, 0);
	memcpy(pLockedData, verts, sizeof(VertexData) * VERTEX_COUNT);
	m_pVertexBuffer->Unlock();
	pLockedData = NULL;

	//Copy index data into index buffer
	m_pIndexBuffer->Lock(0, sizeof(short) * INDEX_COUNT, &pLockedData, 0);
	memcpy(pLockedData, indices, sizeof(short) * INDEX_COUNT);
	m_pIndexBuffer->Unlock();
	pLockedData = NULL;

	return true;
}

void ParticleQuad::Render(float a_dt, IDirect3DDevice9* a_pDevice, const RenderParams& a_renderParams)
{
	if (m_pVertexBuffer && m_pIndexBuffer)
	{
		// Set our world matrix
		a_pDevice->SetTransform(D3DTS_WORLD, &m_worldMatrix);

		// Tell D3D about our vertex data
		a_pDevice->SetStreamSource(0, m_pVertexBuffer, 0, sizeof(VertexData));
		a_pDevice->SetFVF(VERTEX_FORMAT);

		a_pDevice->SetIndices(m_pIndexBuffer);

		const char* SHADER_NAME = "BillboardParticle";
		Shader* pShader = ShaderMgr::GetInstance().Find(SHADER_NAME);
		if(pShader)
		{
			ID3DXEffect* pEffect = pShader->GetEffect();
			if(pEffect)
			{
				pEffect->SetTechnique("RenderTex1RedIntensity");

				//Set texture global variable
				pEffect->SetTexture("g_texture", m_pTex);

				pEffect->SetValue("g_eyePos", Renderer::GetInstance().GetActiveCamera()->GetEyePos(), sizeof(D3DXVECTOR3));
				pEffect->SetFloat("g_alpha", m_alpha);
				pEffect->SetFloat("g_colour", (float)m_colour);
				pEffect->SetFloat("g_scale", m_rot);

				//Set matrix global variables
				//Calculate a combined world*view*proj matrix for the vertex shader
				D3DXMATRIX worldViewProj = m_worldMatrix*a_renderParams.GetViewMatrix()*a_renderParams.GetProjMatrix();
				pEffect->SetMatrix("g_worldViewProj", &worldViewProj);
				pEffect->SetMatrix("g_worldMat", &m_worldMatrix);

				//Render with shader
				UINT passCount = 0;
				if(pEffect->Begin(&passCount, 0) == D3D_OK)
				{
					for(UINT passIndex = 0; passIndex < passCount; ++passIndex)
					{		
						if(pEffect->BeginPass(passIndex) == D3D_OK)
						{
							//Draw the cube
							a_pDevice->DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP, 0, 0, VERTEX_COUNT, 0, 2);
							pEffect->EndPass();
						}
					}
					pEffect->End();
				}
			}
		}
		
	}
}
void ParticleQuad::SetWorldMatrix(const D3DXMATRIX& a_newWorldMat) 
{ 
	m_worldMatrix = a_newWorldMat;
}
const D3DXMATRIX& ParticleQuad::GetWorldMatrix() const
{
	return m_worldMatrix; 
}